#include "lv_drv_conf.h"

#if USE_CRANE_LCD_MIPI_VIDEO
#include <stdio.h>

#include "../common/utils.h"
#include "../../board.h"

#define APB_SPARE       (0xD4090000)

#define APB_SPARE9_REG  (APB_SPARE + 0x120)
#define APB_SPARE10_REG (APB_SPARE + 0x124)
#define APB_SPARE11_REG (APB_SPARE + 0x128)

typedef struct
{
    //unsigned pll_no;
    unsigned pll_freq;
    unsigned pll_reg[6];
}s_pll_setting, *ps_pll_setting;

s_pll_setting g_pll2_setting[] =
{
    // VCXO = 26MHz
    /* {freq  {pll_reg5, pll_reg6, pll_reg7, pll_reg8, pll_div_int, pll_div_frc} }*/
    /*pll2 1600M*/     {1600, {0x61,    0xCD,   0x50,    0x80,     0x3E,     0xE27627}  },
    /*pll2 1740M*/     {1740, {0x61,    0xCD,   0x50,    0x80,     0x43,     0xFB13B1}  },
    /*pll2 1960M*/     {1960, {0x62,    0xCD,   0x50,    0x80,     0x4B,     0x189D8A}  },
    /*pll2 2300M*/     {2300, {0x64,    0xDD,   0x50,    0x80,     0x2C,     0x0EC4EC}  },
    /*pll2 1800M*/     {1800, {0x61,    0xCD,   0x50,    0x80,     0x45,     0x0EC4EC}  },
    /*pll2 2000M*/     {2000, {0x62,    0xDD,   0x50,    0x80,     0x26,     0x1D89D9}  },
    /*pll2 2080M*/     {2080, {0x63,    0xDD,   0x50,    0x80,     0x28,     0x000000}  },
    /*pll2 2100M*/     {2100, {0x63,    0xDD,   0x50,    0x80,     0x28,     0x189D8A}  },
    /*pll2 2500M*/     {2500, {0x64,    0xDD,   0x50,    0x80,     0x30,     0x04EC4F}  },
    /*pll2 3000M*/     {3000, {0x66,    0xDD,   0x50,    0x80,     0x3A,     0xEC4EC5}  }
};

void lcd_phy_pll2_fc(unsigned pll2_vco)
{
    unsigned inx = 0;
    unsigned reg_val = 0;
    unsigned freq_found_flag = 0;

    for(inx = 0; inx < sizeof(g_pll2_setting)/sizeof(s_pll_setting); inx++)
    {
        if(pll2_vco == g_pll2_setting[inx].pll_freq)
        {
            printf("Found inx=%d in g_pll2_setting[]\n", inx);
            freq_found_flag = 1;
            break;
        }
    }

    if(!freq_found_flag)
    {
        printf("!!! WARNING !!! NOT Found pll_freq=%d in g_pll2_setting[], it's default 2133MHz\n", pll2_vco);
        return;
    }

    printf("Before set: APB_SPARE9_REG @[0x%08X]=[0x%08X]\n", APB_SPARE9_REG, readl(APB_SPARE9_REG));
    reg_val = readl(APB_SPARE9_REG);
    reg_val &= ~(0xFFFFFFFF); // clear bit[31:0]
    reg_val |= (g_pll2_setting[inx].pll_reg[0] << 0)  | \
               (g_pll2_setting[inx].pll_reg[1] << 8)  | \
               (g_pll2_setting[inx].pll_reg[2] << 16) | \
               (g_pll2_setting[inx].pll_reg[3] << 24);
    writel(reg_val, APB_SPARE9_REG);
    printf("After set: APB_SPARE9_REG @[0x%08X]=[0x%08X] vs exp[0x%8X]\n", APB_SPARE9_REG, readl(APB_SPARE9_REG), reg_val);

    printf("Before set: APB_SPARE11_REG @[0x%08X]=[0x%08X]\n", APB_SPARE11_REG, readl(APB_SPARE11_REG));
    reg_val =  0;
    reg_val |= (g_pll2_setting[inx].pll_reg[4]<<24) | (g_pll2_setting[inx].pll_reg[5]<<0);
    reg_val |=  BIT(31);
    writel(reg_val, APB_SPARE11_REG);
    printf("After set: APB_SPARE11_REG @[0x%08X]=[0x%08X] vs exp[0x%08X]\n", APB_SPARE11_REG, readl(APB_SPARE11_REG), reg_val);

    //pll2 enable
    writel(readl(APB_SPARE10_REG)|0x3f, APB_SPARE10_REG);
}

unsigned get_pll2_vco_freq(void)
{
    unsigned reg_val = 0;
    unsigned pll2_vco = 2133; // Default PLL2 freq is 2133MHz
    unsigned inx = 0;

    reg_val = readl(APB_SPARE11_REG);

    for(inx = 0; inx < sizeof(g_pll2_setting)/sizeof(s_pll_setting); inx++)
    {
        if((reg_val & 0xFFFFFF) == g_pll2_setting[inx].pll_reg[5])
        {
            pll2_vco = g_pll2_setting[inx].pll_freq;
            break;
        }
    }

    if(pll2_vco == 0)
    {
        printf("!!! WARNING !!! PLL2 is not supported as in the list\n");
    }

    return pll2_vco;
}

#endif
